package com.cdhkppm.job;

import com.cdhkppm.entity.ProjectProductRelationDO;
import com.cdhkppm.service.IssueHelperService;
import com.cdhkppm.service.ProjectProductRelationService;
import com.cdhkppm.utils.IbaAttributeUtils;
import com.github.pagehelper.PageInfo;
import com.hustcad.plm.basic.log.LogEventEnum;
import com.hustcad.plm.pdm.common.model.dto.search.SearchColumnDTO;
import com.hustcad.plm.pdm.common.model.dto.search.SearchTypeDTO;
import com.hustcad.plm.pdm.container.model.dto.search.ProjectEntityParamDTO;
import com.hustcad.plm.pdm.container.model.vo.search.ProjectEntityVO;
import com.hustcad.plm.pdm.core.util.RemoteUtils;
import com.hustcad.plm.pdm.security.entity.SecurityUser;
import com.hustcad.plm.pdm.security.util.JwtTokenUtil;
import com.hustcad.plm.rpm.model.dto.active.TyppmActiveTreeDTO;
import com.hustcad.plm.rpm.service.plan.TyppmPlanActiveService;
import com.ty.basic.constant.TableTypeConstrant;
import com.ty.basic.entity.org.UserDO;
import com.ty.basic.service.snow.SnowflakeIdComponent;
import com.ty.basic.session.TyAccountContext;
import com.ty.ppm.api.service.org.UserService;
import com.ty.ppm.model.utils.Tools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author yfq
 * @apiNote
 */

@Slf4j
@Component
public class ProjectProductAutoUpdateJob {

    @Resource
    private TyppmPlanActiveService typpmPlanActiveService;

    @Resource
    private SnowflakeIdComponent snowflakeIdComponent;

    @Resource
    private IbaAttributeUtils ibaAttributeUtils;
    @Resource
    private UserService userService;
    @Value("${tysoft.PDM.queryProjectByCondition:}")
    private String queryProjectByCondition;
    @Resource
    private RemoteUtils remoteUtils;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private ProjectProductRelationService projectProductRelationService;

    @Resource
    private IssueHelperService issueHelperService;

    @Retryable(
            value = Exception.class,
            maxAttempts = 3,
            backoff = @Backoff(delay = 2000, multiplier = 2)
    )
    @Transactional(rollbackFor = Exception.class)
    @Scheduled(cron = "0 0 2 * * ?")
    public void autoUpdateProjectProductRelation() throws InterruptedException {
        long start = System.currentTimeMillis();
        initSystemContext();
        ProjectEntityParamDTO params = buildProjectSearchParams();
        params.setColumns(buildColumns());
        PageInfo<ProjectEntityVO> pageInfo = this.remoteUtils.postRequest2PageInfo(
                this.queryProjectByCondition, ProjectEntityVO.class, params);

        RequestContextHolder.resetRequestAttributes();

        List<ProjectEntityVO> activeProjects = pageInfo.getList().stream()
                .filter(item -> Integer.valueOf(1).equals(item.getCompletionStatus()))
                .collect(Collectors.toList());

        List<BigInteger> oidList = activeProjects.stream()
                .map(ProjectEntityVO::getPlanOid)
                .collect(Collectors.toList());


        Map<BigInteger, String> projectNameMap = activeProjects.stream()
                .collect(Collectors.toMap(ProjectEntityVO::getPlanOid, ProjectEntityVO::getName));

        for (BigInteger activeOid : oidList) {

            String projectNameFromPage = projectNameMap.get(activeOid);

            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("rootOID", activeOid);
            paramsMap.put("rootOTYPE", TableTypeConstrant.TY_PLAN_OTYPE);
            paramsMap.put("markfordelete", 0L);

            List<TyppmActiveTreeDTO> treeDTOList = typpmPlanActiveService.queryActiveTreeDTOListByParams(paramsMap);
            if (treeDTOList == null || treeDTOList.isEmpty()) {
                log.error("项目 {} 未找到计划树", activeOid);
                continue;
            }

            TyppmActiveTreeDTO targetNode = treeDTOList.stream()
                    .filter(dto -> dto.getName() != null && dto.getName().contains("项目内单机设备"))
                    .findFirst()
                    .orElse(null);

            if (targetNode == null) {
                log.error("项目 {} 未找到【项目内单机设备】任务", activeOid);
                continue;
            }

            String targetOid = targetNode.getOid();

            List<TyppmActiveTreeDTO> targetList = treeDTOList.stream()
                    .filter(dto -> dto.getParentOID() != null && dto.getParentOID().equals(targetOid))
                    .collect(Collectors.toList());

            if (targetList.isEmpty()) {
                log.info("项目 {} 的【项目内单机设备】没有第一级子节点", activeOid);
                continue;
            }

            List<ProjectProductRelationDO> relationList = new ArrayList<>();
            for (TyppmActiveTreeDTO activeTreeDTO : targetList) {
                projectProductRelationService.delete(activeTreeDTO.getContainerOID());
                ProjectProductRelationDO ado = new ProjectProductRelationDO();
                ado.setOid(snowflakeIdComponent.getInstance().nextId());
                ado.setProjectOid(activeTreeDTO.getContainerOID());

                ado.setProjectName(projectNameFromPage);

                ado.setPlanName(activeTreeDTO.getName());

                String jobOID = activeTreeDTO.getJobOID();
                String jobOTYPE = activeTreeDTO.getJobOTYPE();

                String quantity = ibaAttributeUtils.getSingleAttrValue(new BigInteger(jobOID), jobOTYPE, "quantity");
                ado.setQuantity(quantity);

                String productName = ibaAttributeUtils.getSingleAttrValue(new BigInteger(jobOID), jobOTYPE, "productName");
                ado.setProductName(productName);
                ado.setStatus("1");

                String remark = ibaAttributeUtils.getSingleAttrValue(new BigInteger(jobOID), jobOTYPE, "BEIZHU");
                ado.setRemark(remark);

                relationList.add(ado);
            }

            projectProductRelationService.batchAdd(relationList);

            long executionTime = System.currentTimeMillis() - start;
            String timeMessage = "执行接口 autoUpdateProjectProductRelation 耗时: " + executionTime + "ms";
            issueHelperService.recordAuditLog(timeMessage, "", LogEventEnum.COMPLETED, executionTime + "ms");
        }
    }



    @Recover
    public void recover(Exception e) {
        log.error("执行接口 autoUpdateProjectProductRelation 出错", e);
        issueHelperService.recordAuditLog("" ,e.getMessage(), LogEventEnum.COMPLETED, 0 +"ms");
    }





    private void  initSystemContext() throws InterruptedException {
        UserDO systemUser = userService.selectOneByOID(Tools.toBigInteger("105"));
        TyAccountContext.setUser(systemUser);
        TyAccountContext.setIgnoreAuth(true);

        SecurityUser securityUser = new SecurityUser(systemUser.getName());
        String token = this.jwtTokenUtil.generateToken(securityUser);
        TyAccountContext.setToken(token);

        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request, response));
        this.jwtTokenUtil.setTokenHeader(token);
    }




    public ProjectEntityParamDTO buildProjectSearchParams() {

        ProjectEntityParamDTO params = new ProjectEntityParamDTO();
        params.setConditionJoint("and");
        params.setNeedCount(false);
        params.setNeedSort(true);
        params.setPageNum(1);
        params.setPageSize(100000);

        List<SearchTypeDTO> typeList = new ArrayList<>();
        typeList.add(buildSearchType(TableTypeConstrant.TY_PROJECT_TYPE, "327175971096821760"));
        typeList.add(buildSearchType(TableTypeConstrant.TY_PLAN_OTYPE, "327176006605799424"));

        params.setTypeList(typeList);

        return params;
    }


    private SearchTypeDTO buildSearchType(String typeInthid, String oid) {
        SearchTypeDTO dto = new SearchTypeDTO();
        dto.setTypeInthid(typeInthid);
        dto.setTypeOid(new BigInteger(oid));
        return dto;
    }

    private List<SearchColumnDTO> buildColumns() {

        List<SearchColumnDTO> list = new ArrayList<>();

        list.add(buildColumn("projectNumber", "项目编码", "303"));
        list.add(buildColumn("name", "名称", "280"));
        list.add(buildColumn("completionStatus", "项目状态", "90"));
        list.add(buildColumn("percentWorkComplete", "进度", "130"));
        list.add(buildColumn("curMileStoneName", "里程碑阶段", "130"));
        list.add(buildColumn("typeDefName", "类型", "130"));
        list.add(buildColumn("startDate", "计划开始时间", "120"));
        list.add(buildColumn("finishDate", "计划完成时间", "120"));
        list.add(buildColumn("projectManager", "项目经理", "110"));
        list.add(buildColumn("finishDateDeff", "剩余天数", "120"));
        list.add(buildColumn("createstamp", "创建时间", "150"));
        list.add(buildColumn("healthStatus", "健康状态", "110"));
        list.add(buildColumn("phase", "当前阶段", "110"));

        return list;
    }


    private SearchColumnDTO buildColumn(String propertyName, String displayName, String width) {
        SearchColumnDTO dto = new SearchColumnDTO();
        dto.setPropertyName(propertyName);
        dto.setDisplayName(displayName);
        dto.setWidth(width);
        dto.setSortable(false);
        dto.setMasterProperty(false);
        dto.setVirtual(false);
        dto.setForeignColumnMaster(false);
        dto.setFieldList(new ArrayList<>());
        return dto;
    }




}
